package com.warrior.superdata.handler;

import com.warrior.superdata.constants.CommonConstant;
import com.warrior.superdata.mysql.service.ApiInfoService;
import com.warrior.superdata.cache.ApiInfoCacheMap;
import com.warrior.superdata.controller.RequestHandlerController;
import com.warrior.superdata.enums.Method;
import com.warrior.superdata.mysql.entity.dto.ApiInfoDetailDto;
import com.warrior.superdata.mysql.entity.dto.ApiParamDto;
import com.warrior.superdata.util.ApiUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Description:
 * @ClassName: MappingHandler.java
 * @date: 2022/2/23 16:50
 * @author xujian
 */
@Component
@Slf4j
public class MappingHandler {

    @Autowired
    private RequestHandlerController requestHandlerController;

    @Autowired
    @Lazy
    private RequestMappingHandlerMapping requestMappingHandlerMapping;

    @Autowired
    private ApiInfoService apiInfoService;

    public void handlerAllApiMapping() {
        List<ApiInfoDetailDto> apiInfoList = apiInfoService.getApiInfoList(null);
        if (!CollectionUtils.isEmpty(apiInfoList)) {
            apiInfoList.forEach(apiInfo -> {
                handlerApi(apiInfo);
            });
        }
    }

    private RequestMethod getRequestMethod(String method) {
        if (Method.GET.getValue().equals(method)) {
            return RequestMethod.GET;
        } else if (Method.POST.getValue().equals(method)) {
            return RequestMethod.POST;
        } else if (Method.PUT.getValue().equals(method)) {
            return RequestMethod.PUT;
        } else if (Method.DELETE.getValue().equals(method)) {
            return RequestMethod.DELETE;
        }
        return null;
    }

    public void handlerApi(ApiInfoDetailDto apiInfoDetailDto) {
        try {
            apiInfoDetailDto.setDatasourceType(apiInfoDetailDto.getDatasourceDto().getType());
            List<ApiParamDto> params = apiInfoDetailDto.getParams();
            //必传url的参数
            List<String> paramNames = params.stream().filter(item ->
                 CommonConstant.PARAM_REQUIRED == item.getIsRequired() && CommonConstant.API_PARAM_BODY != item.getParamBodyType()
            ).map(ApiParamDto::getParamName).collect(Collectors.toList());
            RequestMappingInfo.Builder paths = paths(apiInfoDetailDto.getUrl(), getRequestMethod(apiInfoDetailDto.getMethod()),
                    paramNames.toArray(new String[paramNames.size()]));
            requestMappingHandlerMapping.registerMapping(paths.build(), requestHandlerController, RequestHandlerController.class.getDeclaredMethod("invoke",
                    HttpServletRequest.class, HttpServletResponse.class));
            log.info("{} {} 接口注册成功", apiInfoDetailDto.getMethod(), apiInfoDetailDto.getUrl());
            ApiInfoCacheMap.API_INFO_MAP.put(ApiUtil.getApiUrl(apiInfoDetailDto), apiInfoDetailDto);
        } catch (Exception e) {
            e.printStackTrace();
            log.info("{} {} 接口注册失败,errMsg:{}", apiInfoDetailDto.getMethod(), apiInfoDetailDto.getUrl(), e.getMessage());
        }
    }

    public void handlerRemoveApi(ApiInfoDetailDto apiInfoDetailDto) {
        try {
            List<ApiParamDto> params = apiInfoDetailDto.getParams();
            //必传url的参数
            List<String> paramNames = params.stream().filter(item ->
                    CommonConstant.PARAM_REQUIRED == item.getIsRequired() && CommonConstant.API_PARAM_BODY != item.getParamBodyType()
            ).map(ApiParamDto::getParamName).collect(Collectors.toList());
            RequestMappingInfo.Builder paths = paths(apiInfoDetailDto.getUrl(), getRequestMethod(apiInfoDetailDto.getMethod()),
                    paramNames.toArray(new String[paramNames.size()]));
            requestMappingHandlerMapping.unregisterMapping(paths.build());
            log.info("{} {} 接口取消成功", apiInfoDetailDto.getMethod(), apiInfoDetailDto.getUrl());
            ApiInfoCacheMap.API_INFO_MAP.remove(ApiUtil.getApiUrl(apiInfoDetailDto));
        } catch (Exception e) {
            e.printStackTrace();
            log.info("{} {} 接口取消成失败,errMsg:{}", apiInfoDetailDto.getMethod(), apiInfoDetailDto.getUrl(), e.getMessage());
        }
    }

    private RequestMappingInfo.Builder paths(String name, RequestMethod method, String... params) {
        RequestMappingInfo.Builder builder = RequestMappingInfo.paths(name);
        builder.methods(method);
        builder.params(params);
        return builder;
    }

}
